#coding: utf-8

# Copyright (c) P SOFTHOUSE. All rights reserved.

import maya.cmds as cmds
import maya.mel as mel
import socket
import sys
#import maya.app.general.CommandPort

PCL_DEFAULT_PORT = 5821

class Listen(object):
    def __init__(self):
        self.port = None

    def __del__(self):
        self.commandPortListenEnd()

    def currentPort(self):
        return self.port

    def commandPortListenStart(self):
        self.commandPortListenEnd()

        commandPortBase = PCL_DEFAULT_PORT
        for port in range(commandPortBase, commandPortBase + 100):
            commandPortName = ':{}'.format(port)
            try:
                cmds.commandPort(returnNumCommands=True, name=commandPortName, sourceType='mel', prefix='batchRender -status')
                self.port = port
                break
            except:
                pass

    def commandPortListenEnd(self):
        if self.port is None:
            return
        try:
            commandPortName = ':{}'.format(self.port)
            cmds.commandPort(name=commandPortName, close=True)
        except:
            pass


class Client(object):
    def __init__(self):
        self.sock = None
        self.pid = mel.eval('getpid')

    def __del__(self):
        self.commandPortClientEnd()

    # 進捗状況送信用のポートに接続する
    def commandPortClientStart(self, port):
        self.commandPortClientEnd()
        if port is None:
            return
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.settimeout(1.0)
            self.sock.connect(('127.0.0.1', port))
        except:
            self.commandPortClientEnd()

    # 進捗状況送信用のポートを切断する
    def commandPortClientEnd(self):
        if self.sock is None:
            return
        try:
            self.sock.close()
            self.sock = None
        except:
            pass

    # 進捗状況を送信する
    def sendProgress(self, progress, filename):
        if self.sock is None:
            return
        try:
            dat = u'{} {} {}'.format(progress, self.pid, filename.decode(sys.getfilesystemencoding())) # 第２パラメータに渡すべき値が不明だが、おそらくプロセスID
            self.sock.send(dat.encode('utf-8'))
            recv = self.sock.recv(4096)
        except socket.timeout:
            pass
        except:
            pass


listen = Listen()
client = Client()


# 進捗状況を送信する
# pencil4lineRenderコマンドから呼び出されます
def sendProgress(progress, filename):
    global client
    client.sendProgress(progress, filename)




# レンダリング可能レイヤーをソートして取得する
def getRenderableLayers():
    layers_all = mel.eval('string $renderLayers[]=`listConnections renderLayerManager.renderLayerId`; sortLayers($renderLayers);')
    layers = [layer for layer in layers_all if cmds.getAttr(layer + '.renderable')]
    return layers


def _parseMelOption(option_str):

    def _argtype(option):
        arg_types = (
            (['-cam', '-camera'      ], str),
            (['-cf' , '-currentFrame'], bool),
            (['-f'  , '-frame'       ], int),
            (['-h'  , '-height'      ], int),
            (['-w'  , '-width'       ], int),
            (['-l'  , '-layer'       ], str),
            (['-nrv', '-noRenderView'], bool),
        )
        for arg in arg_types:
            if option in arg[0]:
                return (arg[0][1][1:], arg[1])
        return None, None

    kwargs = {}
    options = option_str.strip().split(" ")
    #print options
    #return
    i, n = 0, len(options)
    while i < n:
        _kw, _type = _argtype(options[i])
        if _kw:
            i += 1
            if i >= n:
                break
            #print options[i]
            #print type(options[i])
            kwargs[_kw] = _type(options[i])
        i += 1
    return kwargs


def pencil4lineRender(width, height, doShadows, doGlowPass, camera, options):
    kwargs = _parseMelOption(options)
    kwargs['width'] = width
    kwargs['height'] = height
    kwargs['camera'] = camera
    kwargs['currentFrame'] = True
#    print 'pencil4lineRender {}'.format(kwargs)
    result = cmds.pencil4lineRender(**kwargs) # reutrn string
    if isinstance(result, (list, tuple)):
        return result[-1] if len(result) > 0 else ''
    return result


def pencil4lineSequenceRender(width, height, camera, saveToRenderView):
    ret = mel.eval('mayaRenderSequence({}, {}, "{}", "{}");'.format(width, height, camera, saveToRenderView))
    return int(ret) # 0:成功   1:失敗


def pencil4lineBatchRenderOptionsString():
    # Render.exeに渡される文字列
    #
    # pencil4lineRenderer.xml は基本的にmayaBatchRenderProcedureを呼び出すだけです。
    # mayaBatchRenderProcedure はレイヤー毎にレンダリングするので、
    # スムーズ変換はレイヤー毎に行われる（レンダリングの前後にだけスムーズ変換を行うようにできれば効率が良い）
    #
    num_threads = 0
    try:
        num_threads = mel.eval('global int $gNumProcessorsForBatchRender;$temp=$gNumProcessorsForBatchRender')
    except:
        pass
    port = listen.currentPort()
    if port is not None:
        return ' -r pencil4line -n {} -pl:port {} '.format(num_threads, port)
    else:
        return ' -r pencil4line -n {} '.format(num_threads)


def pencil4lineBatchRender(option):
    kwargs = _parseMelOption(option)
    port = None
    if cmds.objExists('pencilBatchNode.pencilCommandPort'):
        port = cmds.getAttr('pencilBatchNode.pencilCommandPort')
        kwargs['port'] = port
    if cmds.objExists('pencilBatchNode.pencilRenderElementsOnly'):
        reo = cmds.getAttr('pencilBatchNode.pencilRenderElementsOnly')
        kwargs['reo'] = reo
#    print 'pencil4lineRender {}'.format(kwargs)
    client.commandPortClientStart(port)
    cmds.pencil4lineRender(**kwargs)
    client.commandPortClientEnd()


def pencil4lineCommandRender(option):
    kwargs = _parseMelOption(option)
    cmds.pencil4lineRender(**kwargs)


def pencil4lineBatchStop():
    cmds.batchRender()


def pencil4lineBatchShow():
    cmds.batchRender(showImage=True)
